package com.yanqu.road.server.manager.grandchild;

import com.yanqu.road.entity.grandchild.GrandChildExamOpenTime;
import com.yanqu.road.entity.grandchild.GrandChildExamOpenTimeParam;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.logic.bussiness.grandchild.GrandChildBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.utils.ConfigHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public class GrandChildExamConfigMgr extends TempMgr {

    // 大锁
    private static final Object lock = new Object();


    // 区服ID，分组ID
    private static Map<Long, Integer> serverGroupMap;
    // 分组ID，List区服ID
    private static Map<Integer, List<Long>> groupServerMap;

    // 开启时间
    private static List<GrandChildExamOpenTime> openTimeList = new ArrayList<>();
    private static GrandChildExamOpenTime curOpenTime = null;

    // ===========================================================

    /**
     * 刷新开启状态
     */
    private static void refreshCurOpenTime() {
        long now = System.currentTimeMillis();
        ArrayList<GrandChildExamOpenTime> openTimes = new ArrayList<>(openTimeList);
        // 找正在进行的
        for (GrandChildExamOpenTime tmp : openTimes) {
            if (tmp.getBegin() <= now && now < tmp.getEnd()) {
                curOpenTime = tmp;
                return;
            }
        }
        // 找下一个
        GrandChildExamOpenTime next = null;
        for (GrandChildExamOpenTime tmp : openTimes) {
            if (tmp.getBegin() > now) {
                if (next == null || tmp.getBegin() < next.getBegin()) {
                    next = tmp;
                }
            }
        }
        curOpenTime = next; // 可以弄为null
    }

    /**
     * 刷新开启配置
     */
    public static void refreshOpenTimeList() {
        long now = System.currentTimeMillis();

        // 获取参数
        List<String> tmpList = StringUtils.stringToStringList(GameConfig.GRAND_CHILD_EXAM_OPEN_TIME, "\\|");
        List<GrandChildExamOpenTimeParam> openTimeParamList = tmpList.stream().map(GrandChildExamOpenTimeParam::new).collect(Collectors.toList());

        // 解析成现在的时间
        List<GrandChildExamOpenTime> tmpOpenTimeList = new ArrayList<>();
        for (GrandChildExamOpenTimeParam openTimeParam : openTimeParamList) {
            tmpOpenTimeList.add(createExamOpenTime(now, openTimeParam));
        }

        openTimeList = tmpOpenTimeList;
        // 刷新下当前的
        refreshCurOpenTime();

        // 打印日期
        try {
            getLogger().info("grand child exam time config = {}", GameConfig.GRAND_CHILD_EXAM_OPEN_TIME);
            for (GrandChildExamOpenTime openTime : new ArrayList<>(openTimeList)) {
                getLogger().info("grand child exam time [{}] : [{}] - [{}]",
                        openTime.getParam(),
                        DateHelper.date2String(new Date(openTime.getBegin())),
                        DateHelper.date2String(new Date(openTime.getEnd()))
                );
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取当前开放时间
     */
    public static GrandChildExamOpenTime getCurOpenTime() {
        long now = System.currentTimeMillis();

        // 空值、已结束，刷新下
        if (curOpenTime == null || curOpenTime.getEnd() < now) {
            synchronized (lock) {
                if (curOpenTime == null || curOpenTime.getEnd() < now) {
                    refreshOpenTimeList();
                }
            }
        }

        // 在时间内才返回
        if (curOpenTime != null && curOpenTime.getBegin() <= now && now < curOpenTime.getEnd()) {
            return curOpenTime;
        }
        return null;
    }

    /**
     * 获取开始时间
     * （关闭时间内，返回下次开启时间）
     *
     * @return 没有配置时间，返回0
     */
    public static long getBeginTime() {
        getCurOpenTime(); // 刷新下
        GrandChildExamOpenTime tmp = curOpenTime;
        if (tmp != null) {
            return tmp.getBegin();
        }
        return 0L;
    }

    /**
     * 现在是否开放
     */
    public static boolean isOpen() {
        return getCurOpenTime() != null;
    }

    /**
     * 计算下次开启时间（正在开启的返回当前时间）
     */
    private static GrandChildExamOpenTime createExamOpenTime(long now, GrandChildExamOpenTimeParam param) {
        long zeroTime = DateHelper.getZeroTimeStamp(now);
        long weekTime = DateHelper.DAY_MILLIONS * 7;

        // 获取今天周几
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setTimeInMillis(zeroTime);
        int day = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        day = day == 0 ? 7 : day;

        // 先随便拿本周内的时间
        long beginTime = zeroTime + DateHelper.DAY_MILLIONS * (param.getBeginDay() - day) + param.getBeginTime();
        long endTime = zeroTime + DateHelper.DAY_MILLIONS * (param.getEndDay() - day) + param.getEndTime();

        // 结束时间不能小于开始时间
        if (endTime <= beginTime) {
            endTime += weekTime;
        }

        // 没开始，先往前移一周，如果过期再移回来
        if (now < beginTime) {
            beginTime -= weekTime;
            endTime -= weekTime;
        }

        // 过期的话加一周
        if (endTime < now) {
            beginTime += weekTime;
            endTime += weekTime;
        }

        return new GrandChildExamOpenTime(param.getParam(), beginTime, endTime);
    }

    // ===========================================================

    /**
     * 获取分组内区服List
     */
    public static List<Long> getServerList(int groupId) {
        if (groupServerMap.containsKey(groupId)) {
            return new ArrayList<>(groupServerMap.get(groupId));
        }
        return new ArrayList<>();
    }

    /**
     * 获取分组ID
     */
    public static int getGroupId(long serverId) {
        if (serverGroupMap.containsKey(serverId)) {
            return serverGroupMap.get(serverId);
        }
        return 0;
    }

    /**
     * 获取Map
     */
    public static Map<Integer, List<Long>> getGroupServerMap() {
        return groupServerMap;
    }

    /**
     * 修改分组配置
     */
    private static void changeGroupConfig() {
        // 刷新分组配置
        int channelId = ConfigHelper.getInt("channelId");
        if (channelId != 0) {
            Map<Integer, List<Long>> tmpGroupMap = GrandChildBussiness.getGrandChildGroupConfigMap(channelId);
            Map<Long, Integer> tmpServerMap = new ConcurrentHashMap<>();
            for (Map.Entry<Integer, List<Long>> entry : tmpGroupMap.entrySet()) {
                int groupId = entry.getKey();
                for (Long serverId : entry.getValue()) {
                    tmpServerMap.put(serverId, groupId);
                }
            }
            groupServerMap = tmpGroupMap;
            serverGroupMap = tmpServerMap;
        }
    }

    // ===========================================================

    @Override
    public boolean init() throws Exception {
        refreshOpenTimeList();
        changeGroupConfig();
        return true;
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        changeGroupConfig();
        GrandChildMgr.checkGroupChange();
        int channelId = ConfigHelper.getInt("channelId");
        GrandChildMgr.syncExamConfigMsg(ServerListMgr.getOpenServerList(channelId).stream().map(ServerInfo::getServerId).collect(Collectors.toList()));
        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }
}
